package cn.lili.mybatis.util;

import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.ObjectFieldEnum;
import cn.lili.common.security.enums.SceneEnums;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * 场景工具类
 *
 * @author liushuai(liushuai711 @ gmail.com)
 * @version v4.0
 * @Description: 场景工具类
 * @since 2023/4/11 14:25
 */

public class SceneHelp {


    private SceneHelp() {
        throw new IllegalStateException("Utility class");
    }


    /**
     * 场景鉴权
     */
    public static void sceneHandler() {
        sceneHandler(SceneEnums.MANAGER);
    }

    /**
     * 场景鉴权
     *
     * @param sceneEnums 场景
     */
    public static void sceneHandler(SceneEnums sceneEnums) {
        if (!UserContext.getCurrentUser().getScene().equals(sceneEnums)) {
            throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
        }
    }

    /**
     * 格式化对象
     *
     * @param entity 模型
     */
    public static void objectHandler(Object entity) {
        if (UserContext.getCurrentUser() == null) {
            return;
        }
        switch (Objects.requireNonNull(UserContext.getCurrentUser()).getScene()) {
            case MANAGER -> setField(entity, SceneEnums.MANAGER.value(), "-1");
            case STORE -> setField(entity, SceneEnums.STORE.value(), UserContext.getCurrentUser().getExtendId());
            case SUPPLIER -> setField(entity, SceneEnums.SUPPLIER.value(), UserContext.getCurrentUser().getExtendId());
            case MEMBER -> setField(entity, SceneEnums.MEMBER.value(), UserContext.getCurrentUser().getId());
            case URBAN_SUBSTATION -> setField(entity, SceneEnums.URBAN_SUBSTATION.value(), UserContext.getCurrentUser().getExtendId());
            default -> setField(entity, SceneEnums.SYSTEM.value(), "-2");
        }
    }

    /**
     * 模型鉴权，鉴定当前用户是否有权限操作该模型
     *
     * @param entity 模型
     */
    public static void objectAuthentication(Object entity) {

        switch (Objects.requireNonNull(UserContext.getCurrentUser()).getScene()) {
            case STORE -> equalsField(entity, SceneEnums.STORE.value(), UserContext.getCurrentUser().getExtendId());
            case SUPPLIER -> equalsField(entity, SceneEnums.SUPPLIER.value(), UserContext.getCurrentUser().getExtendId());
            case MEMBER -> equalsField(entity, SceneEnums.MEMBER.value(), UserContext.getCurrentUser().getId());
            case URBAN_SUBSTATION -> equalsField(entity, SceneEnums.URBAN_SUBSTATION.value(), UserContext.getCurrentUser().getExtendId());
            default -> {
                break;
            }
        }
    }

    /**
     * 模型鉴权，鉴定当前用户是否有权限操作该模型
     *
     * @param entity 模型
     */
    public static void objectAuthenticationCancel(Object entity, AuthUser authUser) {

        switch (Objects.requireNonNull(authUser).getScene()) {
            case STORE -> equalsField(entity, SceneEnums.STORE.value(), authUser.getExtendId());
            case SUPPLIER -> equalsField(entity, SceneEnums.SUPPLIER.value(), authUser.getExtendId());
            case MEMBER -> equalsField(entity, SceneEnums.MEMBER.value(), authUser.getId());
            case URBAN_SUBSTATION -> equalsField(entity, SceneEnums.URBAN_SUBSTATION.value(), authUser.getExtendId());
            default -> {
                break;
            }
        }
    }


    /**
     * 模型鉴权，鉴定当前用户是否有权限操作该模型
     *
     * @param entity          模型
     * @param objectFieldEnum 比对字段
     */
    public static void objectAuthentication(Object entity, ObjectFieldEnum... objectFieldEnum) {

        String currentId = UserContext.getCurrentId();
        if (Arrays.stream(objectFieldEnum).noneMatch(item -> equalsField(entity, item, currentId))) {
            throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
        }

    }

    /**
     * 设置字段值
     *
     * @param entity   模型·
     * @param scene    场景
     * @param extendId 扩展ID
     */
    public static void equalsField(Object entity, String scene, String extendId) {

        Method[] methods = entity.getClass().getMethods();
        methods = ArrayUtils.addAll(methods, entity.getClass().getSuperclass().getMethods());


        try {
            for (Method method : methods) {
                if (method.getName().equals("getScene")) {
                    if (!scene.equals(method.invoke(entity))) {
                        throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
                    }
                }
                if (method.getName().equals("getExtendId")) {
                    if (!extendId.equals(method.invoke(entity))) {
                        throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
                    }
                }
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 设置字段值
     *
     * @param entity          模型·
     * @param objectFieldEnum 判定字段
     * @param extendId        判定值
     */
    public static Boolean equalsField(Object entity, ObjectFieldEnum objectFieldEnum, String extendId) {

        Method[] methods = entity.getClass().getMethods();
        methods = ArrayUtils.addAll(methods, entity.getClass().getSuperclass().getMethods());


        try {
            for (Method method : methods) {
                if (method.getName().equals(objectFieldEnum.getField())) {
                    if (extendId.equals(method.invoke(entity))) {
                        return true;
                    }
                }
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    /**
     * 设置字段值
     *
     * @param entity   模型
     * @param scene    场景
     * @param extendId 扩展ID
     */
    public static void setField(Object entity, String scene, String extendId) {

        Method[] methods = entity.getClass().getMethods();
        methods = ArrayUtils.addAll(methods, entity.getClass().getSuperclass().getMethods());

        try {
            for (Method method : methods) {
                if (method.getName().equals("setScene")) {
                    method.invoke(entity, scene);
                }
                if (method.getName().equals("setExtendId")) {
                    method.invoke(entity, extendId);
                }
            }
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询条件处理
     *
     * @param wrapper 查询条件
     */
    public static void queryHandler(AbstractWrapper wrapper) {
        queryHandler(wrapper, null, false);
    }

    /**
     * 查询条件处理
     * 如果联合查询，不确认使用哪个表的字段，则传入tableName字段即可。
     *
     * @param wrapper   查询条件
     * @param tableName 表名
     */
    public static void queryHandler(AbstractWrapper wrapper, String tableName) {

        queryHandler(wrapper, tableName, false);

    }

    /**
     * 查询条件处理
     *
     * @param wrapper            查询条件
     * @param managerIgnoreWhere 是否忽略管理员的查询参数
     */
    public static void queryHandler(AbstractWrapper wrapper, Boolean managerIgnoreWhere) {
        queryHandler(wrapper, null, managerIgnoreWhere);
    }

    /**
     * 查询条件处理
     *
     * @param wrapper            查询条件
     * @param tableName          表名
     * @param managerIgnoreWhere 是否忽略管理员的查询参数
     */
    public static void queryHandler(AbstractWrapper wrapper, String tableName, Boolean managerIgnoreWhere) {

        String sceneField = StringUtils.isEmpty(tableName) ? "scene" : tableName + "." + "scene";
        String extendIdField = StringUtils.isEmpty(tableName) ? "extend_id" : tableName + "." + "extend_id";

        switch (Objects.requireNonNull(UserContext.getCurrentUser()).getScene()) {
            case MANAGER:
                if (Boolean.TRUE.equals(managerIgnoreWhere)) {
                    break;
                }
                wrapper.eq(sceneField, SceneEnums.MANAGER.value());
                wrapper.eq(extendIdField, "-1");
                break;
            case STORE:
                wrapper.eq(sceneField, SceneEnums.STORE.value());
                wrapper.eq(extendIdField, UserContext.getCurrentUser().getExtendId());
                break;
            case SUPPLIER:
                wrapper.eq(sceneField, SceneEnums.SUPPLIER.value());
                wrapper.eq(extendIdField, UserContext.getCurrentUser().getExtendId());
                break;
            case MEMBER:
                wrapper.eq(sceneField, SceneEnums.MEMBER.value());
                wrapper.eq(extendIdField, UserContext.getCurrentUser().getExtendId());
                break;
            case URBAN_SUBSTATION:
                wrapper.eq(sceneField, SceneEnums.URBAN_SUBSTATION.value());
                wrapper.eq(extendIdField, UserContext.getCurrentUser().getExtendId());
            default:
                break;
        }
    }
}
